#include "../../../include/online/KeyRecommander.hpp"
#include "../../../include/online/Configuration.hpp"
#include "../../../include/online/Dictionary.hpp"
/* #include "../../../include/nlohmann/json.hpp" */
#include <nlohmann/json.hpp>
#include <string>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
#include <unistd.h>
#include <utility>

using std::priority_queue;
using std::string;
using std::vector;
using std::map;
using std::pair;
using std::cout;
using std::endl;
using namespace nlohmann;

KeyRecommander::KeyRecommander()
{

}

KeyRecommander::KeyRecommander(string &queryWord, const TcpConnectionPtr &conn)
: _queryWord(queryWord), _conn(conn){

}

void KeyRecommander::clearDataMember() {
    //每次查询前将所有非必要数据清空
    _result.clear();
    _indexID.clear();   
    _result.clear();    //清空结果队列
}

//执行查询
string KeyRecommander::doQuery() {
    Dictionary *pdict = Dictionary::getInstance();
    const unordered_map<string, set<int>> &indexTable = pdict->getIndexTable();
    /* cout << "KeyRecommander::doQuery::indexTable.size() = " << indexTable.size() << endl; */
    
    string index;
    
    clearDataMember();

    //按逐个字符查找，找到以后将set<int>加入indexId
    for(size_t idx = 0; idx < _queryWord.length(); ++idx) {
        size_t nBytes = nBytesCode(_queryWord[idx]);
        index = _queryWord.substr(idx, nBytes);
        idx += (nBytes - 1);    //为啥减一，因为for循环还会自增
        
        auto it = indexTable.find(index);   //在索引表找索引
        if(it != indexTable.end()){
            _indexID.insert(it->second.begin(), it->second.end());
        }
    }

    if(_indexID.size() == 0){
        //未找到，通知服务器
        return serializeNothing();
    }

    //进入优先级队列，取出排好序的keyword
    statistic();

    const int recommandKeyNum = atoi((Configuration::getInstance()->getConfigMap()["recommandKeyNum"]).c_str());
    
    for(int i = 0; i < recommandKeyNum; ++i) {
        if(!_resultQue.empty()){
            //结果存入vector
            /* cout << "resQueue.top().getword() = " << _resultQue.top().getWord() << endl; */ 
            _result.push_back(_resultQue.top().getWord());
            _resultQue.pop();    //从优先级队列弹出
        }
    }

    //遍历查询结果
    cout << "最后输出推荐结果" << endl;
    cout << "_result.size() = " << _result.size() << endl;
    for(auto &elem : _result) {
        cout << elem << endl;
    }

    //将结果序列化为一个字符串对象
    return serialize();
}

//进行计算
void KeyRecommander::statistic() {
    //字典类采用单例模式
    Dictionary *pdict = Dictionary::getInstance();
    const unordered_map<string, int> &dict = pdict->getDict();

    /* cout << "KeyRecommander::statistic: dict.size() = " << dict.size() << endl; */

    vector<pair<string, int>> dict2;
    dict2.reserve(20000);
    //将map的内容复制到vector
    for(auto it = dict.begin(); it != dict.end(); ++it){
        dict2.push_back(*it);
    }

    /* cout << "vector::dict2.size() = " << dict2.size() << endl; */

    /* sleep(7); */
    vector<QueryResult> queres; 
    for (auto it = _indexID.begin(); it != _indexID.end(); ++it) {
        int dist = editDistance(_queryWord, dict2[*it].first);

        /* cout << "KeyRecommander::statistic: " << dict2[*it].first << " " << dist << endl; */

        QueryResult result(dict2[*it].first, dict2[*it].second, dist);
        _resultQue.push(result);
        queres.push_back(result);
    }

    /* sleep(5); */

    /* cout << "vector::queres.size() = " << queres.size() << endl; */
    
    /* for(auto &elem : queres) { */
    /*     cout << elem.getWord() << endl; */
    /* } */
    /* sleep(2); */
}

//响应客户端请求
void KeyRecommander::response() {
    //将json对象序列化以后得字符串发送给客户端    
}

//序列化空结果(找不到关键词)
string KeyRecommander::serializeNothing() {
    json jsonObj;
    /* jsonObj["msgId"] = 200; */
    jsonObj["msg"] = json("no corresponding keyword");
    return jsonObj.dump();
}

//序列化结果(找到关键字)
string KeyRecommander::serialize(){
    json jsonObj = _result;
    /* jsonObj["msgID"] = 100; */
    /* json msg = _result; */
    /* jsonObj["msg"] = msg; */

    return jsonObj.dump();
}

/* int main() { */
/*     TcpConnectionPtr conn = nullptr; */
/*     string queryWord; */
/*     std::cin >> queryWord; */
/*     KeyRecommander kr(queryWord, nullptr); */
/*     kr.doQuery(); */
/* } */
